using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Gadgeteer;

namespace G2Tech.Gadgeteer.MountaineerLed
{
    /// <summary>
    /// Board RGB Led 
    /// </summary>
    public class BoardRGBLed
    {
        #region Private Fields

        private static bool _initialized = false;

        private static Microsoft.SPOT.Hardware.PWM _ledR, _ledG, _ledB;

        private static Color _setColor;
        private static Color _actualColor;

        private static Timer _blinkingTimer = null;
        private static bool[] _blinkPattern = null;
        private static int _blinkSlot = 0;

        private static Timer _fadingTimer = null;
        private static bool _fadingBlackToLight = true;
        private static int _fadingStep = 0;
        private const int _fadingSteps = 20;

        #endregion

        #region Internal Methods

        private static void initialize()
        {
            if (!_initialized)
            {
                _ledR = new PWM(G2Tech.Gadgeteer.MountaineerLed.MountaineerHardware.PwmRed, 1000, 0, false);
                _ledG = new PWM(G2Tech.Gadgeteer.MountaineerLed.MountaineerHardware.PwmGreen, 1000, 0, false);
                _ledB = new PWM(G2Tech.Gadgeteer.MountaineerLed.MountaineerHardware.PwmBlue, 1000, 0, false);
                _initialized = true;
            }
        }

        /// <summary>
        /// update PWM to reflect the actual color
        /// </summary>
        private static void updatePWM(Color color)
        {
            initialize();

            if (color != Color.Black)
            {
                _ledB.Stop();
                _ledG.Stop();
                _ledR.Stop();

                _ledB.DutyCycle = (double)((float)color.B / (float)255);
                _ledG.DutyCycle = (double)((float)color.G / (float)255);
                _ledR.DutyCycle = (double)((float)color.R / (float)255);

                _ledB.Start();
                _ledG.Start();
                _ledR.Start();
            }
            else
            {
                _ledB.Stop();
                _ledG.Stop();
                _ledR.Stop();
            }
        }

        /// <summary>
        /// blinking timer ticks
        /// </summary>
        /// <param name="timer"></param>
        static void _blinkingTimer_Tick(Timer timer)
        {
            if (_blinkSlot == _blinkPattern.Length)
            {
                _blinkSlot = 0;
            }

            if (_blinkPattern[_blinkSlot])
            {
                _actualColor = _setColor;
            }
            else
            {
                _actualColor = Color.Black;
            }

            updatePWM(_actualColor);

            _blinkSlot++;
        }

        /// <summary>
        /// fading timer ticks
        /// </summary>
        /// <param name="timer"></param>
        static void _fadingTimer_Tick(Timer timer)
        {
            if (_fadingBlackToLight)
            {
                _actualColor = HSLHelper.IncreaseLuminescence(_actualColor, 1 / _fadingSteps);
            }
            else
            {
                _actualColor = HSLHelper.DecreaseLuminescence(_actualColor, 1 / _fadingSteps);
            }

            updatePWM(_actualColor);

            if (_fadingStep == _fadingSteps)
            {
                if (_fadingBlackToLight)
                    _fadingBlackToLight = false;
                else
                    _fadingBlackToLight = true;
            }

            _fadingStep++;
        }

        #endregion

        #region Public Methods
        
        /// <summary>
        /// Set a Static Color
        /// </summary>
        /// <param name="color"></param>
        public static void SetStaticColor(Color color)
        {
            if (_blinkingTimer != null)
            {
                _blinkingTimer.Stop();
            }

            _setColor = _actualColor = color;

            updatePWM(_setColor);
        }

        /// <summary>
        /// Set a Static Color
        /// </summary>
        /// <param name="hslColor"></param>
        public static void SetStaticColor(HSLColor hslColor)
        {
            SetStaticColor(hslColor.ToColor());
        }


        /// <summary>
        /// Start to Blink the led
        /// </summary>
        /// <param name="color"></param>
        /// <param name="period"></param>
        /// <param name="blinkPattern"></param>
        public static void BlinkColor(Color color, int intervalMilliseconds, bool[] blinkPattern)
        {
            _setColor = color;

            if (blinkPattern == null)
            {
                _blinkPattern = new bool[] { false, true };
            }
            else
            {
                _blinkPattern = blinkPattern;
            }

            _blinkSlot = 0;
            int blinkingTimerTick = intervalMilliseconds / (_blinkPattern.Length + 1);
            
            if (_blinkingTimer == null)
            {
                _blinkingTimer = new Timer(blinkingTimerTick);
                _blinkingTimer.Tick += new Timer.TickEventHandler(_blinkingTimer_Tick);
            }
            else
            {
                _blinkingTimer.Stop();
                _blinkingTimer.Interval = new TimeSpan(0,0,0,0,blinkingTimerTick);
            }
                
            _blinkingTimer.Start();
        }

        /// <summary>
        /// Start to Blink the led
        /// </summary>
        /// <param name="hslColor"></param>
        /// <param name="period"></param>
        /// <param name="blinkPattern"></param>
        public static void BlinkColor(HSLColor hslColor, int intervalMilliseconds, bool[] blinkPattern)
        {
            BlinkColor(hslColor.ToColor(), intervalMilliseconds, blinkPattern);
        }


        /// <summary>
        /// Start to fade color.
        /// </summary>
        /// <param name="color"></param>
        /// <param name="intervalMilliseconds"></param>
        /// <param name="blackToLight"></param>
        public static void FadeColor(Color color, int intervalMilliseconds, bool blackToLight)
        {
            ShutOff();

            _fadingBlackToLight = blackToLight;
            _setColor = color;
            _actualColor = Color.Black;

            if (_fadingTimer != null)
            {
                _fadingTimer.Tick += new Timer.TickEventHandler(_fadingTimer_Tick);
                _fadingTimer.Stop();
                _fadingTimer = null;
            }

            _fadingTimer = new Timer(intervalMilliseconds / _fadingSteps);
            _fadingTimer.Tick += new Timer.TickEventHandler(_fadingTimer_Tick);
            _fadingTimer.Start();
        }

        /// <summary>
        /// Shut off the led.
        /// </summary>
        public static void ShutOff()
        {
            SetStaticColor(Color.Black);
        }

        #endregion

        #region Public Property
        
        /// <summary>
        /// Obtain the Actual Color.
        /// </summary>
        public static Color ActualColor
        {
            get
            {
                return _actualColor;
            }
        } 

        #endregion
    }
}
